package com.gitee.zzh.sqllineage.ref;

import com.gitee.zzh.sqllineage.util.ColumnInfoUtils;
import com.gitee.zzh.sqllineage.util.SqlStringUtils;
import com.gitee.zzh.sqllineage.vo.TransformVO;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class TableRef extends SqlStringUtils {

    public static Set<String> getFirstTable(TransformVO transformVO, Set<String> insertSet) {
        String text = transformVO.getText();
        String tableNameTemp = transformVO.getTableNameTemp();
        Set<String> tempSet = new HashSet<>();
        setUpdateField(insertSet, tempSet, transformVO);
        List<String> list = getInsertSqlText(text, tableNameTemp);
        String createAsSqlText = getCreateAsSqlText(text, tableNameTemp);
        if(!isBlank(createAsSqlText)) {
            list.add(createAsSqlText);
        }
        for (String sqlText : list) {
            sqlText = sqlText.substring(sqlText.indexOf(" SELECT "));
            List<String> selectList = getUnienSelectList(sqlText, true);
            for (String selectText : selectList) {
                Set<String> tempSet1 = getSelectInfo(selectText, insertSet, transformVO);
                tempSet.addAll(tempSet1);
            }
        }
        return tempSet;
    }

    public static void getTable(TransformVO transformVO, Set<String> tableColumnTempSet, Set<String> insertSet) {
        String text = transformVO.getText();
        Set<String> tempSet1 = new HashSet<>();
        while (!tableColumnTempSet.isEmpty()) {
            Set<String> tempSet2 = new HashSet<>();
            Set<String> tempSet3 = new HashSet<>();
            for (String tableColumnCombine : tableColumnTempSet) {
                String[] tableColumnComArr = tableColumnCombine.split(" ");
                String tableName = tableColumnComArr[0];
                String tableNameTemp = tableColumnComArr[1];
                transformVO.setTableName(tableName);
                transformVO.setTableNameTemp(tableNameTemp);
                setUpdateField(insertSet, tempSet2, transformVO);
                List<String> list = getInsertSqlText(text, tableNameTemp);
                String createAsSqlText = getCreateAsSqlText(text, tableNameTemp);
                if(!isBlank(createAsSqlText)) {
                    list.add(createAsSqlText);
                }
                for (String sqlText : list) {
                    sqlText = sqlText.substring(sqlText.indexOf(" SELECT "));
                    List<String> selectList = getUnienSelectList(sqlText, true);
                    for (String selectText : selectList) {
                        Set<String> tempSet4 = getSelectInfo1(tableColumnComArr, selectText, insertSet, transformVO);
                        tempSet2.addAll(tempSet4);
                    }
                }
            }
            for (String s : tempSet2) {
                if(!tempSet1.contains(s)) {
                    tempSet3.add(s);
                }
            }
            tempSet1.addAll(tempSet3);
            tableColumnTempSet = tempSet3;
        }
    }

    private static Set<String> getSelectInfo(String selectText, Set<String> insertSet, TransformVO transformVO) {
        Set<String> tableSet = getTableBySelect(selectText);
        String text = transformVO.getText();
        List<String> sourceTableList = tableSet.stream().filter(s->!isTempTable(text, s)).collect(Collectors.toList());
        List<String> tempTableList = tableSet.stream().filter(s->isTempTable(text, s)).collect(Collectors.toList());
        Set<String> tempSet = new HashSet<>();
        if(selectText.contains("_MANUAL_S_")) {
            setSelectSelectFields(selectText, insertSet, tempSet, transformVO);
        }
        add(sourceTableList, insertSet, transformVO);
        add(tempTableList, tempSet, transformVO);
        return tempSet;
    }
    private static Set<String> getSelectInfo1(String[] tableNameTempComArr, String selectText, Set<String> insertSet, TransformVO transformVO) {
        Set<String> tableSet = getTableBySelect(selectText);
        String text = transformVO.getText();
        List<String> sourceTableList = tableSet.stream().filter(s->!isTempTable(text, s)).collect(Collectors.toList());
        List<String> tempTableList = tableSet.stream().filter(s->isTempTable(text, s)).collect(Collectors.toList());
        Set<String> tempSet = new HashSet<>();
        transformVO.setTableName(tableNameTempComArr[0]);
        if(selectText.contains("_MANUAL_S_")) {
            setSelectSelectFields(selectText, insertSet, tempSet, transformVO);
        }
        add(sourceTableList, insertSet, transformVO);
        add(tempTableList, tempSet, transformVO);
        return tempSet;
    }
    private static void setSelectSelectFields(String selectText, Set<String> insertSet, Set<String> tempSet, TransformVO transformVO) {
        if(!selectText.contains("_MANUAL_S_")) {
            return;
        }
        String text = transformVO.getText();
        String[] textArr = transformVO.getTextArr();
        String[] arr = selectText.split("[() |=,]");
        for (String s : arr) {
            if(!s.contains("_MANUAL_S_")) {
                continue;
            }
            for (String textPart : textArr) {
                textPart = textPart.trim();
                if(!textPart.contains("CREATE TABLE " + s + " AS SELECT ")) {
                   continue;
                }
                String selectSql = textPart.substring(("CREATE TABLE " + s + " AS SELECT ").length());
                List<String> selectList = getUnienSelectList(selectSql, true);
                for (String sqlText : selectList) {
                    Set<String> tableSet = getTableBySelect(sqlText);
                    List<String> sourceTableList = tableSet.stream().filter(st->!isTempTable(text, st)).collect(Collectors.toList());
                    List<String> tempTableList = tableSet.stream().filter(st->isTempTable(text, st)).collect(Collectors.toList());
                    add(sourceTableList, insertSet, transformVO);
                    add(tempTableList, tempSet, transformVO);
                }
            }
        }
    }

    public static void setUpdateField(Set<String> insertSet, Set<String> tempSet, TransformVO transformVO) {
        String text = transformVO.getText();
        String tableName = transformVO.getTableName();
        String tableNameTemp = transformVO.getTableNameTemp();
        List<String> sqlList = getUpdateSqlText(text, tableNameTemp);
        List<Map<String, String>> targetList = ColumnInfoUtils.getColumnsInfo(transformVO, tableNameTemp);
        if(targetList.isEmpty()) {
            return;
        }
        for (String textUpdate : sqlList) {
            String left = substringBySymbol(textUpdate.trim(), " WHERE ");
            String sourceTable = getUpdateTable(left);
            String sCombine = tableName + " " + sourceTable;
            if(!text.contains("DROP TABLE IF EXISTS " + sourceTable + ";")) {
                insertSet.add(sCombine);
            } else {
                tempSet.add(sCombine);
            }
        }
    }

    private static void add(List<String> tableList, Set<String> insertOrTempSet, TransformVO transformVO) {
        String tableName = transformVO.getTableName();
        for (String sourceTable : tableList) {
            insertOrTempSet.add(tableName + " " + sourceTable);
        }
    }
}
